/********************************************************
 *
 * FILE NAME:   smartingeegclientagent.cpp
 *
 * DESCRIPTION:
 *  Module for communication with Smarting EEG Server
 *
 ********************************************************/

/********************************************************/
/*              Includes                                */
/********************************************************/
#include "smartingeegclientagent.h"

#include <QDebug>
#include <QtQml>

/********************************************************/
/*              Defines                                 */
/********************************************************/
#define SMARTINGEEGCLIENTAGENT__RESPONSE_HEAD '>'
#define SMARTINGEEGCLIENTAGENT__RESPONSE_TAIL '<'
#define SMARTINGEEGCLIENTAGENT__RESPONSE_MAX_SIZE 83    // Bytes

#define SMARTINGEEGCLIENTAGENT__OK_RESPONSE_SIZE 4      // Bytes
#define SMARTINGEEGCLIENTAGENT__ERROR_RESPONSE_SIZE 5   // Bytes
#define SMARTINGEEGCLIENTAGENT__DATA_RESPONSE_SIZE 83   // Bytes

#define SMARTINGEEGCLIENTAGENT__BUFFER_SIZE 100000      // Bytes

#define SMARTINGEEGCLIENTAGENT__COMMAND_DELAY 50        // ms

#define SMARTINGEEGCLIENTAGENT__BUFFER_OVERLOADED_LOWER_THRESHOLD 50 // Bytes
#define SMARTINGEEGCLIENTAGENT__BUFFER_OVERLOADED_UPPER_THRESHOLD 200 // Bytes

/********************************************************/
/*              Macros                                  */
/********************************************************/

/********************************************************/
/*              Typedefs                                */
/********************************************************/

/********************************************************/
/*              Local Functions Declarations (LOCAL)    */
/********************************************************/

/********************************************************/
/*              Global Variables (GLOBAL/IMPORT)        */
/********************************************************/

/********************************************************/
/*              Local Module Variables (MODULE)         */
/********************************************************/

/********************************************************/
/*              Local File Variables (LOCAL)            */
/********************************************************/

/********************************************************/
/*              Functions Definitions (LOCAL/GLOBAL)    */
/********************************************************/
SmartingEEGClientAgent::SmartingEEGClientAgent(QObject *parent) : QObject(parent)
{
    _workerThread = new QThread(this);
    _workerThread->start();

    _worker = new SmartingEEGClientAgentWorker(*this);
    _worker->moveToThread(_workerThread);

    _btDevice = new QBluetoothLocalDevice(this);
    if(_btDevice->isValid())
    {
        _btDevice->powerOn();
    }

    _btDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
    connect(_btDiscoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)), this, SLOT(_onDeviceDiscovered(QBluetoothDeviceInfo)));

    _btSocket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol, this);
    connect(_btSocket, SIGNAL(connected()), this, SLOT(_onConnectedToServer()));
    connect(_btSocket, SIGNAL(disconnected()), this, SIGNAL(disconnectedFromServer()));
    connect(_btSocket, SIGNAL(readyRead()), _worker, SLOT(_onReadyRead()));

    _mode = NORMAL_MODE;
    for(int i = 0; i < SMARTINGEEGCLIENTAGENT__NUM_OF_CHANNELS; ++i)
    {
        _channelEnabled[i] = false;
    }
    _impedanceMeasurementEnabled = false;

    for(int i = 0; i < SMARTINGEEGCLIENTAGENT__NUM_OF_CHANNELS; ++i)
    {
        _channelBuff[i] = new Buffer<sample_t>(SMARTINGEEGCLIENTAGENT__BUFFER_SIZE);
        _channelUnprocessed[i] = 0;
        _channelMtx[i] = new QMutex(QMutex::NonRecursive);
        _channelNotEmpty[i] = new QWaitCondition();
        _channelNotFull[i] = new QWaitCondition();
        _channelOSig[i] = new SmartingEEGClientAgentOSignal(*_channelBuff[i], _channelUnprocessed[i], *_channelMtx[i], *_channelNotEmpty[i], *_channelNotFull[i]);
    }

    _syncBuff = new Buffer<sample_t>(SMARTINGEEGCLIENTAGENT__BUFFER_SIZE);
    _syncUnprocessed = 0;
    _syncMtx = new QMutex(QMutex::NonRecursive);
    _syncNotEmpty = new QWaitCondition();
    _syncNotFull = new QWaitCondition();
    _syncOSig = new SmartingEEGClientAgentOSignal(*_syncBuff, _syncUnprocessed, *_syncMtx, *_syncNotEmpty, *_syncNotFull);

    _gyroXBuff = new Buffer<sample_t>(SMARTINGEEGCLIENTAGENT__BUFFER_SIZE);
    _gyroXUnprocessed = 0;
    _gyroXMtx = new QMutex(QMutex::NonRecursive);
    _gyroXNotEmpty = new QWaitCondition();
    _gyroXNotFull = new QWaitCondition();
    _gyroXOSig = new SmartingEEGClientAgentOSignal(*_gyroXBuff, _gyroXUnprocessed, *_gyroXMtx, *_gyroXNotEmpty, *_gyroXNotFull);

    _gyroYBuff = new Buffer<sample_t>(SMARTINGEEGCLIENTAGENT__BUFFER_SIZE);
    _gyroYUnprocessed = 0;
    _gyroYMtx = new QMutex(QMutex::NonRecursive);
    _gyroYNotEmpty = new QWaitCondition();
    _gyroYNotFull = new QWaitCondition();
    _gyroYOSig = new SmartingEEGClientAgentOSignal(*_gyroYBuff, _gyroYUnprocessed, *_gyroYMtx, *_gyroYNotEmpty, *_gyroYNotFull);

    _gyroZBuff = new Buffer<sample_t>(SMARTINGEEGCLIENTAGENT__BUFFER_SIZE);
    _gyroZUnprocessed = 0;
    _gyroZMtx = new QMutex(QMutex::NonRecursive);
    _gyroZNotEmpty = new QWaitCondition();
    _gyroZNotFull = new QWaitCondition();
    _gyroZOSig = new SmartingEEGClientAgentOSignal(*_gyroZBuff, _gyroZUnprocessed, *_gyroZMtx, *_gyroZNotEmpty, *_gyroZNotFull);

    _batteryBuff = new Buffer<sample_t>(SMARTINGEEGCLIENTAGENT__BUFFER_SIZE);
    _batteryUnprocessed = 0;
    _batteryMtx = new QMutex(QMutex::NonRecursive);
    _batteryNotEmpty = new QWaitCondition();
    _batteryNotFull = new QWaitCondition();
    _batteryOSig = new SmartingEEGClientAgentOSignal(*_batteryBuff, _batteryUnprocessed, *_batteryMtx, *_batteryNotEmpty, *_batteryNotFull);

    _bufferOverloaded = isBufferOverloaded();
}

SmartingEEGClientAgent::~SmartingEEGClientAgent()
{
    delete _workerThread;
    delete _worker;

    delete _btDevice;
    delete _btDiscoveryAgent;
    delete _btSocket;

    delete _syncBuff;
    delete _syncMtx;
    delete _syncNotEmpty;
    delete _syncNotFull;
    delete _syncOSig;

    delete _gyroXBuff;
    delete _gyroXMtx;
    delete _gyroXNotEmpty;
    delete _gyroXNotFull;
    delete _gyroXOSig;

    delete _gyroYBuff;
    delete _gyroYMtx;
    delete _gyroYNotEmpty;
    delete _gyroYNotFull;
    delete _gyroYOSig;

    delete _gyroZBuff;
    delete _gyroZMtx;
    delete _gyroZNotEmpty;
    delete _gyroZNotFull;
    delete _gyroZOSig;

    delete _batteryBuff;
    delete _batteryMtx;
    delete _batteryNotEmpty;
    delete _batteryNotFull;
    delete _batteryOSig;

    for(int i = 0; i < SMARTINGEEGCLIENTAGENT__NUM_OF_CHANNELS; ++i)
    {
        delete _channelBuff[i];
        delete _channelMtx[i];
        delete _channelNotEmpty[i];
        delete _channelNotFull[i];
    }
}

void SmartingEEGClientAgent::registerTypes(const char *uri)
{
    qmlRegisterType<SmartingEEGClientAgent>(uri, 1, 0, "SmartingEEGClientAgent");
}

bool SmartingEEGClientAgent::init()
{
    return _btDevice->isValid();
}

void SmartingEEGClientAgent::startServerDiscovery()
{
    _btDiscoveryAgent->start();
}

void SmartingEEGClientAgent::stopServerDiscovery()
{
    _btDiscoveryAgent->stop();
}

void SmartingEEGClientAgent::connectToServer(const QString &address)
{
#if defined(Q_OS_ANDROID)
    _btSocket->connectToService(QBluetoothAddress(address), QBluetoothUuid(QBluetoothUuid::SerialPort));

#elif defined(Q_OS_LINUX)
    QBluetoothServiceInfo::Sequence btUuid;
    btUuid << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm)) << 1;

    QBluetoothServiceInfo::Sequence btProtocol;
    btProtocol << QVariant::fromValue(btUuid);

    QBluetoothServiceInfo btService;
    btService.setDevice(QBluetoothDeviceInfo(QBluetoothAddress(address), QString("SMARTING"), 0));
    btService.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, btProtocol);

    _btSocket->connectToService(btService);
#endif
}

void SmartingEEGClientAgent::disconnectFromServer()
{
    _btSocket->disconnectFromService();
}

void SmartingEEGClientAgent::startAcquisition()
{
    _btSocket->write(QByteArray(">ON<"));
    QThread::msleep(SMARTINGEEGCLIENTAGENT__COMMAND_DELAY);
}

void SmartingEEGClientAgent::stopAcquisition()
{
    _btSocket->write(QByteArray(">OFF<"));
    QThread::msleep(SMARTINGEEGCLIENTAGENT__COMMAND_DELAY);
}

void SmartingEEGClientAgent::setMode(SmartingEEGClientAgent::mode_e mode)
{
    _mode = mode;

    switch (mode)
    {
        case SmartingEEGClientAgent::NORMAL_MODE:
            _btSocket->write(QByteArray(">NORMAL<"));
            break;

        case SmartingEEGClientAgent::TEST_MODE:
            _btSocket->write(QByteArray(">TEST<"));
            break;
    }
    QThread::msleep(SMARTINGEEGCLIENTAGENT__COMMAND_DELAY);
}

void SmartingEEGClientAgent::enableChannel(quint8 num)
    {
    _channelEnabled[num] = true;

    QByteArray msg(">SC;###<");

    for(quint8 j = 0; j < 3; ++j)
    {
        msg[4 + j] = 0;
        for(quint8 i = 0; i < 8; ++i)
        {
            msg[4 + j] = msg[4 + j] | _channelEnabled[8 * j + i] << i;
        }
    }

    _btSocket->write(msg);
    QThread::msleep(SMARTINGEEGCLIENTAGENT__COMMAND_DELAY);
}

void SmartingEEGClientAgent::disableChannel(quint8 num)
{
    _channelEnabled[num] = false;

    QByteArray msg(">SC;###<");

    for(quint8 j = 0; j < 3; ++j)
    {
        msg[4 + j] = 0;
        for(quint8 i = 0; i < 8; ++i)
        {
            msg[4 + j] = msg[4 + j] | _channelEnabled[8 * j + i] << i;
        }
    }

    _btSocket->write(msg);
    QThread::msleep(SMARTINGEEGCLIENTAGENT__COMMAND_DELAY);
}

void SmartingEEGClientAgent::enableImpedanceMeasurement()
{
    _impedanceMeasurementEnabled = true;

    _btSocket->write(QByteArray(">IMPON<"));
    QThread::msleep(SMARTINGEEGCLIENTAGENT__COMMAND_DELAY);

    _btSocket->write(QByteArray(">REFON<"));
    QThread::msleep(SMARTINGEEGCLIENTAGENT__COMMAND_DELAY);
}

void SmartingEEGClientAgent::disableImpedanceMeasurement()
{
    _impedanceMeasurementEnabled = false;

    _btSocket->write(QByteArray(">REFOFF<"));
    QThread::msleep(SMARTINGEEGCLIENTAGENT__COMMAND_DELAY);

    _btSocket->write(QByteArray(">IMPOFF<"));
    QThread::msleep(SMARTINGEEGCLIENTAGENT__COMMAND_DELAY);
}

bool SmartingEEGClientAgent::isBufferOverloaded()
{
    if(_syncUnprocessed < SMARTINGEEGCLIENTAGENT__BUFFER_OVERLOADED_LOWER_THRESHOLD)
    {
        return false;
    }else if(_syncUnprocessed > SMARTINGEEGCLIENTAGENT__BUFFER_OVERLOADED_UPPER_THRESHOLD)
    {
        return true;
    }else
    {
        return _bufferOverloaded;
    }
}

/*int SmartingEEGClientAgent::batteryStatus()
{
    return _batteryStatus;
}*/

void SmartingEEGClientAgent::_updateBufferOverloaded()
{
    if(_bufferOverloaded != isBufferOverloaded())
    {
        _bufferOverloaded = !_bufferOverloaded;
        emit bufferOverloadedChanged();
    }
}

void SmartingEEGClientAgent::_onDeviceDiscovered(const QBluetoothDeviceInfo &device)
{
    emit serverDiscovered(device.name(), device.address().toString());
}

void SmartingEEGClientAgent::_onConnectedToServer()
{
    QThread::msleep(300);
    emit connectedToServer();
}

SmartingEEGClientAgent::SmartingEEGClientAgentOSignal::SmartingEEGClientAgentOSignal(Buffer<sample_t> &buff, size_t &buffUnprocessed, QMutex &buffMtx, QWaitCondition &buffNotEmpty, QWaitCondition &buffNotFull) : OSignal(0), _buff(buff), _buffUnprocessed(buffUnprocessed), _buffMtx(buffMtx), _buffNotEmpty(buffNotEmpty), _buffNotFull(buffNotFull)
{
}

bool SmartingEEGClientAgent::SmartingEEGClientAgentOSignal::onBurstRequest(size_t burstLength)
{
    /*_buffMtx.lock();
    for(size_t burst = 0; burst < burstLength; ++burst)
    {
        if(_buffUnprocessed == 0)
        {
            _buffNotEmpty.wait(&_buffMtx);
        }

        (*this)[0] = _buff[0];
        this->writeOutSample();

        _buff.rotate(-1);
        --_buffUnprocessed;

        _buffNotFull.wakeAll();
    }
    _buffMtx.unlock();
*/

    for(size_t burst = 0; burst < burstLength; ++burst)
    {
        (*this)[0] = burst;
        this->writeOutSample();
    }
    QThread::currentThread()->msleep(2 * burstLength);

    return true;
}

SmartingEEGClientAgentWorker::SmartingEEGClientAgentWorker(SmartingEEGClientAgent &context) : QObject(0), _context(context)
{
    _readBuff = new char[SMARTINGEEGCLIENTAGENT__BUFFER_SIZE];
    _readUnprocessed = 0;

    _parseBuff = new Buffer<quint8>(SMARTINGEEGCLIENTAGENT__BUFFER_SIZE + SMARTINGEEGCLIENTAGENT__RESPONSE_MAX_SIZE - 1);
    _parseUnprocessed = 0;
}

SmartingEEGClientAgentWorker::~SmartingEEGClientAgentWorker()
{
    delete _readBuff;
    delete _parseBuff;
}

void SmartingEEGClientAgentWorker::_onReadyRead()
{
    Buffer<quint8> &parseBuff = *_parseBuff;

    QBluetoothSocket &btSocket = *_context._btSocket;

    Buffer<sample_t> **channelBuff = _context._channelBuff;
    size_t *channelUnprocessed = _context._channelUnprocessed;
    QMutex **channelMtx = _context._channelMtx;
    QWaitCondition **channelNotEmpty = _context._channelNotEmpty;
    QWaitCondition **channelNotFull = _context._channelNotFull;
    OSignal **channelOSig = (OSignal **) _context._channelOSig;

    Buffer<sample_t> &syncBuff = *_context._syncBuff;
    size_t &syncUnprocessed = _context._syncUnprocessed;
    QMutex &syncMtx = *_context._syncMtx;
    QWaitCondition &syncNotEmpty = *_context._syncNotEmpty;
    QWaitCondition &syncNotFull = *_context._syncNotFull;
    OSignal &syncOSig = *_context._syncOSig;

    Buffer<sample_t> &gyroXBuff = *_context._gyroXBuff;
    size_t &gyroXUnprocessed = _context._gyroXUnprocessed;
    QMutex &gyroXMtx = *_context._gyroXMtx;
    QWaitCondition &gyroXNotEmpty = *_context._gyroXNotEmpty;
    QWaitCondition &gyroXNotFull = *_context._gyroXNotFull;
    OSignal &gyroXOSig = *_context._gyroXOSig;

    Buffer<sample_t> &gyroYBuff = *_context._gyroYBuff;
    size_t &gyroYUnprocessed = _context._gyroYUnprocessed;
    QMutex &gyroYMtx = *_context._gyroYMtx;
    QWaitCondition &gyroYNotEmpty = *_context._gyroYNotEmpty;
    QWaitCondition &gyroYNotFull = *_context._gyroYNotFull;
    OSignal &gyroYOSig = *_context._gyroYOSig;

    Buffer<sample_t> &gyroZBuff = *_context._gyroZBuff;
    size_t &gyroZUnprocessed = _context._gyroZUnprocessed;
    QMutex &gyroZMtx = *_context._gyroZMtx;
    QWaitCondition &gyroZNotEmpty = *_context._gyroZNotEmpty;
    QWaitCondition &gyroZNotFull = *_context._gyroZNotFull;
    OSignal &gyroZOSig = *_context._gyroZOSig;

    Buffer<sample_t> &batteryBuff = *_context._batteryBuff;
    size_t &batteryUnprocessed = _context._batteryUnprocessed;
    QMutex &batteryMtx = *_context._batteryMtx;
    QWaitCondition &batteryNotEmpty = *_context._batteryNotEmpty;
    QWaitCondition &batteryNotFull = *_context._batteryNotFull;
    OSignal &batteryOSig = *_context._batteryOSig;

    while((_readUnprocessed = btSocket.read(_readBuff, SMARTINGEEGCLIENTAGENT__BUFFER_SIZE)) > 0)
    {
        for(int i = 0; i < _readUnprocessed; ++i)
        {
            parseBuff[_parseUnprocessed + i] = _readBuff[i];
        }
        _parseUnprocessed += _readUnprocessed;

        while(_parseUnprocessed > 0)
        {
            if(parseBuff[0] == SMARTINGEEGCLIENTAGENT__RESPONSE_HEAD)
            {
                if((_parseUnprocessed >= SMARTINGEEGCLIENTAGENT__DATA_RESPONSE_SIZE) && \
                    (parseBuff[SMARTINGEEGCLIENTAGENT__DATA_RESPONSE_SIZE - 1] == SMARTINGEEGCLIENTAGENT__RESPONSE_TAIL))
                {
                    // TODO check checksum

                    // data channels
                    for(int channel = 0; channel < SMARTINGEEGCLIENTAGENT__NUM_OF_CHANNELS; ++channel)
                    {
                        channelMtx[channel]->lock();

                        if(channelUnprocessed[channel] == SMARTINGEEGCLIENTAGENT__BUFFER_SIZE)
                        {
                            channelNotFull[channel]->wait(channelMtx[channel]);
                        }

                        qint32 data = 0;
                        for(int part = 0; part < 3; ++part)
                        {
                            data <<= 8;
                            data += parseBuff[1 + channel * 3 + part];
                        }
                        data ^= 0x00800000;

                        (*channelBuff[channel])[channelUnprocessed[channel]] = data * (187500.0 / ((1 << 23) - 1)) - 187470;
                        ++channelUnprocessed[channel];

                        if(channelUnprocessed[channel] >= channelOSig[channel]->burstLength())
                        {
                            channelNotEmpty[channel]->wakeAll();
                        }
                        channelMtx[channel]->unlock();
                    }

                    // sync channel
                    syncMtx.lock();

                    if(syncUnprocessed == SMARTINGEEGCLIENTAGENT__BUFFER_SIZE)
                    {
                        syncNotFull.wait(&syncMtx);
                    }

                    syncBuff[syncUnprocessed] = parseBuff[73];
                    ++syncUnprocessed;

                    if(syncUnprocessed >= syncOSig.burstLength())
                    {
                        syncNotEmpty.wakeAll();
                    }
                    syncMtx.unlock();

                    // gyroX channel
                    gyroXMtx.lock();

                    if(gyroXUnprocessed == SMARTINGEEGCLIENTAGENT__BUFFER_SIZE)
                    {
                        gyroXNotFull.wait(&gyroXMtx);
                    }

                    qint16 gyroX = 0;
                    gyroX += parseBuff[74];
                    gyroX <<= 8;
                    gyroX += parseBuff[75];
                    gyroXBuff[gyroXUnprocessed] = gyroXUnprocessed;// gyroX;
                    ++gyroXUnprocessed;

                    if(gyroXUnprocessed >= gyroXOSig.burstLength())
                    {
                        gyroXNotEmpty.wakeAll();
                    }
                    gyroXMtx.unlock();

                    // gyroY channel
                    gyroYMtx.lock();

                    if(gyroYUnprocessed == SMARTINGEEGCLIENTAGENT__BUFFER_SIZE)
                    {
                        gyroYNotFull.wait(&gyroYMtx);
                    }

                    qint16 gyroY = 0;
                    gyroY += parseBuff[76];
                    gyroY <<= 8;
                    gyroY += parseBuff[77];
                    gyroYBuff[gyroYUnprocessed] = gyroY;
                    ++gyroYUnprocessed;

                    if(gyroYUnprocessed >= gyroYOSig.burstLength())
                    {
                        gyroYNotEmpty.wakeAll();
                    }
                    gyroYMtx.unlock();

                    // gyroZ channel
                    gyroZMtx.lock();

                    if(gyroZUnprocessed == SMARTINGEEGCLIENTAGENT__BUFFER_SIZE)
                    {
                        gyroZNotFull.wait(&gyroZMtx);
                    }

                    qint16 gyroZ = 0;
                    gyroZ += parseBuff[78];
                    gyroZ <<= 8;
                    gyroZ += parseBuff[79];
                    gyroZBuff[gyroZUnprocessed] = gyroZ;
                    ++gyroZUnprocessed;

                    if(gyroZUnprocessed >= gyroZOSig.burstLength())
                    {
                        gyroZNotEmpty.wakeAll();
                    }
                    gyroZMtx.unlock();

                    // battery channel
                    batteryMtx.lock();

                    if(batteryUnprocessed == SMARTINGEEGCLIENTAGENT__BUFFER_SIZE)
                    {
                        batteryNotFull.wait(&batteryMtx);
                    }

                    batteryBuff[batteryUnprocessed] = parseBuff[80];
                    ++batteryUnprocessed;

                    if(batteryUnprocessed >= batteryOSig.burstLength())
                    {
                        batteryNotEmpty.wakeAll();
                    }
                    batteryMtx.unlock();

                    _context._updateBufferOverloaded();

                    parseBuff.rotate(-SMARTINGEEGCLIENTAGENT__DATA_RESPONSE_SIZE);
                    _parseUnprocessed -= SMARTINGEEGCLIENTAGENT__DATA_RESPONSE_SIZE;
                    continue;
                }

                if((_parseUnprocessed >= SMARTINGEEGCLIENTAGENT__ERROR_RESPONSE_SIZE) && \
                    (parseBuff[SMARTINGEEGCLIENTAGENT__ERROR_RESPONSE_SIZE - 1] == SMARTINGEEGCLIENTAGENT__RESPONSE_TAIL))
                {
                    if((parseBuff[1] == 'E') && \
                        (parseBuff[2] == 'R') && \
                        (parseBuff[3] == 'R'))
                    {
                        qDebug() << "ERR";

                        parseBuff.rotate(-SMARTINGEEGCLIENTAGENT__ERROR_RESPONSE_SIZE);
                        _parseUnprocessed -= SMARTINGEEGCLIENTAGENT__ERROR_RESPONSE_SIZE;
                        continue;
                    }
                }

                if((_parseUnprocessed >= SMARTINGEEGCLIENTAGENT__OK_RESPONSE_SIZE) && \
                    (parseBuff[SMARTINGEEGCLIENTAGENT__OK_RESPONSE_SIZE - 1] == SMARTINGEEGCLIENTAGENT__RESPONSE_TAIL))
                {
                    if((parseBuff[1] == 'O') && \
                        (parseBuff[2] == 'K'))
                    {
                        qDebug() << "OK";

                        parseBuff.rotate(-SMARTINGEEGCLIENTAGENT__OK_RESPONSE_SIZE);
                        _parseUnprocessed -= SMARTINGEEGCLIENTAGENT__OK_RESPONSE_SIZE;
                        continue;
                    }
                }

                break;

            }else
            {
                parseBuff.rotate(-1);
                --_parseUnprocessed;
            }
        }
    }
}
